package org.lgiavedoni.android.franq.util.place;

import java.util.Date;
import java.util.List;

import org.lgiavedoni.android.franq.core.bean.WifiNetwork;
import org.lgiavedoni.android.franq.core.position.Position;
import org.lgiavedoni.android.franq.core.position.PositionManager;
import org.lgiavedoni.android.franq.service.config.ConfigService;
import org.lgiavedoni.android.franq.service.config.ConfigService.ConfigKey;
import org.lgiavedoni.android.franq.util.collection.CollectionUtils;

public class PlaceUtil {

	public static boolean areTheSamePlace(Position... positions) {
		if (CollectionUtils.cointansNull(positions))
			return false;
		return areTheSamePlace((List<Position>) CollectionUtils.toList(positions));
	}

	public static boolean areTheSamePlace(List<Position> positions) {
		if (positions == null || positions.size() < 2)
			return false;

		return areTheSamePlaceByNetworks(positions) || areTheSamePlaceByLocation(positions) || areTheSamePlaceByCell(positions);
	}

	private static boolean areTheSamePlaceByNetworks(Position a, Position b) {
		if (a.isUnknowNetworks() || b.isUnknowNetworks())
			return false;

		for (WifiNetwork n : a.getNetworks()) {
			if (b.getNetworks().contains(n))
				return true;
		}
		return false;
	}

	private static boolean areTheSamePlaceByNetworks(List<Position> positions) {
		for (int i = 0; i < positions.size(); i++) {
			Position a = positions.get(i);
			for (int j = 0; j < positions.size(); j++) {
				Position b = positions.get(j);
				if (!areTheSamePlaceByNetworks(a, b)) {
					return false;
				}
			}
		}
		return true;
	}

	private static boolean areTheSamePlaceByLocation(List<Position> positions) {
		for (int i = 0; i < positions.size(); i++) {
			Position a = positions.get(i);
			if (a.isUnknowLocation()) {
				return false;
			}

			for (int j = 0; j < positions.size(); j++) {
				Position b = positions.get(j);
				if (b.isUnknowLocation()) {
					return false;
				}
				// Same scale?
				if (a.getPrecision() == b.getPrecision()) {
					if (distFromInMeters(a, b) > 5)
						return false;

				} else {
					// Different scale
					if (distFromInMeters(a, b) > ConfigService.inst.getValueAsInt(ConfigKey.PLACE_MAX_VALID_DISTANCE)) {
						// the distance is to big
						return false;
					}
				}
			}
		}
		return true;
	}

	private static boolean areTheSamePlaceByCell(List<Position> positions) {
		for (int i = 0; i < positions.size(); i++) {
			Position a = positions.get(i);
			if (a.isUnknowCell()) {
				return false;
			}

			for (int j = 0; j < positions.size(); j++) {
				Position b = positions.get(j);
				if (b.isUnknowCell()) {
					return false;
				}
				if (!a.getCellLocation().equals(b.getCellLocation()))
					return false;
			}
		}
		return true;
	}

	public static boolean stateEnoughTimeInTheLastPlace() {
		Position current = PositionManager.inst.getCurrentPosition();
		if (current == null)
			return false;

		/*
		 * List<Position> lPos = PositionDAO.inst.getAll(); for (int i =
		 * lPos.size() - 1; i > 0; i--) { // for (int i = 0; i < lPos.size();
		 * i++) { Position p = lPos.get(i); if (areTheSamePlace(current, p)) {
		 * if ((current.getCreationDate().getTime() -
		 * p.getCreationDate().getTime()) >
		 * ConfigService.inst.getValueAsLong(ConfigKey.PLACE_MIN_STAY_TIME)) {
		 * return true; } } else { return false; } }
		 */
		if ((new Date().getTime() - current.getCreationDate().getTime()) > ConfigService.inst.getValueAsLong(ConfigKey.PLACE_MIN_STAY_TIME)) {
			return true;
		}
		return false;
	}

	public static float distFromInMeters(Position a, Position b) {
		return distFromInMeters(a.getLatitude(), a.getLongitude(), b.getLatitude(), b.getLongitude());
	}

	public static float distFromInMeters(double lat1, double lng1, double lat2, double lng2) {
		double earthRadius = 3958.75;
		double dLat = Math.toRadians(lat2 - lat1);
		double dLng = Math.toRadians(lng2 - lng1);
		double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
		double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
		double dist = earthRadius * c;

		int meterConversion = 1609;

		return (float) dist * meterConversion;
	}

	public static void main(String a[]) {
		System.out.println(distFromInMeters(52.376729249954224, 4.899457097053528, 52.38161623477936, 4.857233762741089));
		System.out.println(distFromInMeters(52.38161623477936, 4.857233762741089, 52.38150894641876, 4.857512712478638));
		System.out.println(distFromInMeters(52.38150894641876, 4.857512712478638, 52.38154113292694, 4.8574429750442505));

		System.out.println(distFromInMeters(52.376729249954224, 4.899457097053528, 52.38161623477936, 4.857233762741089) > 100);
		System.out.println(distFromInMeters(52.38161623477936, 4.857233762741089, 52.38150894641876, 4.857512712478638) > 100);
		System.out.println(distFromInMeters(52.38150894641876, 4.857512712478638, 52.38154113292694, 4.8574429750442505) > 100);
	}
}
